/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.mocking;

import picounit.Should;
import picounit.When;
import picounit.mocker.Action;
import picounit.mocker.ArrayStubConsequenceMatcher;
import picounit.mocker.BaseStubConsequenceMatcher;
import picounit.mocker.BooleanAction;
import picounit.mocker.BooleanArrayStubConsequenceMatcher;
import picounit.mocker.BooleanStubConsequenceMatcher;
import picounit.mocker.ByteAction;
import picounit.mocker.ByteArrayStubConsequenceMatcher;
import picounit.mocker.ByteStubConsequenceMatcher;
import picounit.mocker.CharAction;
import picounit.mocker.CharArrayStubConsequenceMatcher;
import picounit.mocker.CharStubConsequenceMatcher;
import picounit.mocker.DoubleAction;
import picounit.mocker.DoubleArrayStubConsequenceMatcher;
import picounit.mocker.DoubleStubConsequenceMatcher;
import picounit.mocker.FloatAction;
import picounit.mocker.FloatArrayStubConsequenceMatcher;
import picounit.mocker.FloatStubConsequenceMatcher;
import picounit.mocker.IntAction;
import picounit.mocker.IntArrayStubConsequenceMatcher;
import picounit.mocker.IntStubConsequenceMatcher;
import picounit.mocker.LongAction;
import picounit.mocker.LongArrayStubConsequenceMatcher;
import picounit.mocker.LongStubConsequenceMatcher;
import picounit.mocker.OccurencesMatcher;
import picounit.mocker.PostConsequenceMatcher;
import picounit.mocker.ShortAction;
import picounit.mocker.ShortArrayStubConsequenceMatcher;
import picounit.mocker.ShortStubConsequenceMatcher;
import picounit.mocker.StringAction;
import picounit.mocker.StringArrayStubConsequenceMatcher;
import picounit.mocker.StringStubConsequenceMatcher;
import picounit.mocker.StubConsequenceMatcher;
import picounit.mocker.VoidAction;

@SuppressWarnings("unchecked")
public class Stubber implements When, BaseStubConsequenceMatcher,
	BooleanStubConsequenceMatcher, ByteStubConsequenceMatcher, CharStubConsequenceMatcher,
	DoubleStubConsequenceMatcher, FloatStubConsequenceMatcher, IntStubConsequenceMatcher,
	LongStubConsequenceMatcher, ShortStubConsequenceMatcher, StringStubConsequenceMatcher,
	StubConsequenceMatcher {

	private final ArrayStubber arrayStubber;
	private final CombinedConsequenceMatcher combinedConsequenceMatcher;
	private final Should should;

	public Stubber(ArrayStubber arrayStubber, CombinedConsequenceMatcher combinedConsequenceMatcher,
		Should should) {

		this.arrayStubber = arrayStubber;
		this.combinedConsequenceMatcher = combinedConsequenceMatcher;
		this.should = should;
	}
	
	public BooleanStubConsequenceMatcher calling(boolean ignore) {
		return this;
	}

	public ByteStubConsequenceMatcher calling(byte ignore) {
		return this;
	}

	public CharStubConsequenceMatcher calling(char ignore) {
		return this;
	}

	public DoubleStubConsequenceMatcher calling(double ignore) {
		return this;
	}

	public FloatStubConsequenceMatcher calling(float ignore) {
		return this;
	}

	public IntStubConsequenceMatcher calling(int ignore) {
		return this;
	}

	public LongStubConsequenceMatcher calling(long ignore) {
		return this;
	}

	public ShortStubConsequenceMatcher calling(short ignore) {
		return this;
	}

	public StringStubConsequenceMatcher calling(String ignore) {
		return this;
	}

	@SuppressWarnings("unchecked")
	public <T> StubConsequenceMatcher<T> calling(T ignore) {
		return this;
	}
	
	public BooleanArrayStubConsequenceMatcher calling(boolean[] ignore) {
		return arrayStubber;
	}
	
	public ByteArrayStubConsequenceMatcher calling(byte[] ignore) {
		return arrayStubber;
	}
	
	public CharArrayStubConsequenceMatcher calling(char[] ignore) {
		return arrayStubber;
	}
	
	public DoubleArrayStubConsequenceMatcher calling(double[] ignore) {
		return arrayStubber;
	}
	
	public FloatArrayStubConsequenceMatcher calling(float[] ignore) {
		return arrayStubber;
	}
	
	public IntArrayStubConsequenceMatcher calling(int[] ignore) {
		return arrayStubber;
	}
	
	public LongArrayStubConsequenceMatcher calling(long[] ignore) {
		return arrayStubber;
	}
	
	public ShortArrayStubConsequenceMatcher calling(short[] ignore) {
		return arrayStubber;
	}
	
	public StringArrayStubConsequenceMatcher calling(String[] ignore) {
		return arrayStubber;
	}

	@SuppressWarnings("unchecked")
	public <T> ArrayStubConsequenceMatcher<T> calling(T[] ignore) {
		return arrayStubber;
	}

	public void thenRaise(Throwable toRaise) {
		optionally(combinedConsequenceMatcher.andRaise(toRaise));
	}

	public void thenReturn(boolean returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(byte returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(char returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(double returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(float returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(int returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(long returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(short returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(String returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}

	public void thenReturn(Object returnValue) {
		optionally(combinedConsequenceMatcher.andReturn(returnValue));
	}
	
	public void thenPerform(BooleanAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}
	
	public void thenPerform(ByteAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}
	
	public void thenPerform(CharAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}
	
	public void thenPerform(DoubleAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}
	
	public void thenPerform(FloatAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}
	
	public void thenPerform(IntAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}

	public void thenPerform(LongAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}

	public void thenPerform(ShortAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}

	public void thenPerform(StringAction action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}

	public void thenPerform(Action action) {
		optionally(combinedConsequenceMatcher.andPerform(action));
	}

	public void perform(VoidAction voidAction) {
		optionally(should.perform(voidAction));
	}

	public void raise(Throwable throwable) {
		optionally(should.raise(throwable));
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Implementation
	///////////////////////////////////////////////////////////////////////////////////////////////

	private PostConsequenceMatcher optionally(OccurencesMatcher occurencesMatcher) {
		return occurencesMatcher.optional();
	}
}
